/***************************************************************************
 *   Copyright (C) 2007 by Autostop team                                   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/


// Qt
#include <QDomDocument>
#include <QThread>

// camera
#include "camera.h"

// autostop-common
#include "camera2params.h"

// gcommons
#include "gexception.h"

// gparams
#include "gparams.h"

// libautonet
#include "autopackets.h"

// local
#include "adjusterserver.h"
#include "constants.h"
#include "globaldata.h"




// ===========================================================================
//                              AdjusterServer
// ===========================================================================


// ------------------ AdjusterServer::AdjusterServer() -----------------------
AdjusterServer::AdjusterServer( QObject* pParent ): GNetServer( pParent )
{
		// register packets types used by autonet
	GAutoPacket::registerPackets();
	
	GlobalData::instance()->incConnections(); // say 'halo'
}
// ---------------------------------------------------------------------------


// ------------------ AdjusterServer::~AdjusterServer() ----------------------
AdjusterServer::~AdjusterServer()
{
	GlobalData::instance()->decConnections(); // say 'goodbye'
}
// ---------------------------------------------------------------------------


// ------------------- AdjusterServer::processPacket() -----------------------
void AdjusterServer::processPacket( GNetPacket* pPacket )
{
	if ( pPacket )
	{
		switch ( pPacket->packetType() )
		{
			// incoming params
			case GAutoPacket::PACKET_PARAMS:
				processParams( qobject_cast< GAutoParams * >( pPacket ) );
				break;

			// areas config file
			case GAutoPacket::PACKET_AREAS_CONFIG:
				processAreasConfig( qobject_cast< GAutoAreasConfig * >( pPacket ) );
				break;
				
			// request
			case GAutoPacket::PACKET_REQUEST:
				processRequest( qobject_cast< GAutoRequest * >( pPacket ) );
				break;
				
			// udp target
			case GAutoPacket::PACKET_UDP_HOST_INFO:
				processUdpTarget( qobject_cast< GUDPHostInfo * >( pPacket ) );
				break;

			// ignore others
			default:
				// nothing, only warn
				qWarning("Server::processPacket: unknown packet type: %d",
						 (int)pPacket->packetType() );
		}
	} // pAutoPacket
	else
	{
		qWarning("erver::processPacket: packet null or non GAutoPacket-derrived type");
		return; //maybe throw here?
	}
	
}
// ---------------------------------------------------------------------------


// -------------------- AdjusterServer::processRequest() ---------------------
void AdjusterServer::processRequest( GAutoRequest * pRequest )
{
	// check input.
	if ( ! pRequest )
	{
		return; // TODO maybe throw here
	}
	
	GNetPacketReply * pReply = NULL;
	try
	{
		// handle various requests
		switch( pRequest->requestType() )
		{
			case GAutoRequest::REQUEST_AREAS_CONFIG:
			{
				// create and send reply packet 
				GAutoReplyAreasConfig * pReplyAreasConfig;
				pReplyAreasConfig = new GAutoReplyAreasConfig( pRequest->requestId() );
				pReply = pReplyAreasConfig;
				
				if ( pReplyAreasConfig )
				{
					processRequestAreasConfig( pReplyAreasConfig );
				}
				else
				{
					throw GSysError( tr("Can not allocate packet" ) );
				}
			}
			break;
			
			case GAutoRequest::REQUEST_CAMERA_CONFIG:
			{
				// create and send reply packet 
				GAutoReplyCameraConfig * pReplyCameraConfig;
				pReplyCameraConfig = new GAutoReplyCameraConfig( pRequest->requestId() );
				pReply = pReplyCameraConfig;
				
				if ( pReplyCameraConfig )
				{
					processRequestCameraConfig( pReplyCameraConfig );
				}
				else
				{
					throw GSysError( tr("Can not allocate packet" ) );
				}
			}
			break;
			
			case GAutoRequest::REQUEST_PARAMS:
			{
				// create and send reply packet
				GAutoReplyParams * pReplyParams;
				pReplyParams = new GAutoReplyParams( pRequest->requestId() );
				pReply = pReplyParams;
				
				if( pReplyParams )
				{
					processRequestParams( pReplyParams );
				}
				else
				{
					throw GSysError( tr("Can not allocate packet" ) );
				}
			}
			break;

			case GAutoRequest::REQUEST_FRAME:
			{
				// craete and sen replay packet
				GAutoReplyFrame * pReplyFrame;
				pReplyFrame = new GAutoReplyFrame( pRequest->requestId() );
				pReply = pReplyFrame;
				if( pReplyFrame )
				{
					processRequestFrame( pReplyFrame );
				}
				else
				{
					throw GSysError( tr( "Can not allocate packet." ) );
				}
			}
			break;
			
			default:
				qWarning("Server::processRequest: unknown request: %d",
						 pRequest->requestType()) ; // warn
		}
	}
	catch( const GException& e )
	{
		// TODO handle error
		qWarning( "Exception in Server::processRequest: %s",
				  qPrintable( e.getMessage() ) );
	}

	// send reply
	if ( pReply )
	{
		sendPacket( *pReply );
        delete pReply;
	}

}
// ---------------------------------------------------------------------------


// ------------------- AdjusterServer::passUser() ----------------------------
quint8 AdjusterServer::passUser( const QString & userName,
								 const QString & password
							   )
{
	qDebug() << "userName" << userName;
	qDebug() << "password" << password;
	
	return GNetPacketAuthorizationAnswer::STATUS_OK; // test
}
// ---------------------------------------------------------------------------


// ------------------ AdjusterServer::processAreasConfig() -------------------
void AdjusterServer::processAreasConfig( GAutoAreasConfig * pAreasConfig )
{
		// save new areas config file
	QFile areasConfig( AREAS_CONFIG_FILE );
	
	if( areasConfig.open( QIODevice::WriteOnly | QIODevice::Text) )
	{
		areasConfig.write( pAreasConfig->data() );
	}
	else
	{
		throw GSysError( QString("Could not open file %1 for writing").arg( AREAS_CONFIG_FILE ) );
	}
}
// ---------------------------------------------------------------------------


// ------------- AdjusterServer::processRequestAreasConfig() -----------------
void AdjusterServer::processRequestAreasConfig( GAutoReplyAreasConfig * pReplyAreasConfig )
{
		// reply areas config file
	QFile areasConfig( AREAS_CONFIG_FILE );
	
	if( areasConfig.open( QIODevice::ReadOnly | QIODevice::Text ) )
	{
		pReplyAreasConfig->setData( areasConfig.readAll() );
	}
	else
	{
		//can not open file or file not exists - return empty file 
		pReplyAreasConfig->setData( QByteArray() );
// 		throw GSysError( QString("Could not open file %1 for reading").arg( AREAS_CONFIG_FILE ) );
	}
}
// ---------------------------------------------------------------------------


// ------------------ AdjusterServer::processRequestCameraConfig() -----------
void AdjusterServer::processRequestCameraConfig(
		GAutoReplyCameraConfig * pReplyCameraConfig
											   )
{
		// reply camera config file
	QFile cameraConfig( CAMERA_CONFIG_FILE );
	
	if( cameraConfig.open( QIODevice::ReadOnly | QIODevice::Text ) )
	{
		pReplyCameraConfig->setData( cameraConfig.readAll() );
	}
}
// ---------------------------------------------------------------------------


// ------------------- AdjusterServer::processParams() -----------------------
void AdjusterServer::processParams( GAutoParams * pParams )
{
	Q_ASSERT( pParams );

	try
	{
		pParams->params().saveToFile( PARAMS_CONFIG_FILE );
	}
	catch( const GException & e )
	{
		// TODO handle error
		qWarning( "Exception in Server::processPrams: %s",
				  qPrintable( e.getMessage() )
				);
	}
	
	// write to global data, regardless if file was written or not
	GlobalData::instance()->setParams( pParams->params() );
}
// ---------------------------------------------------------------------------


// ---------------- AdjusterServer::processRequestParams() -------------------
void AdjusterServer::processRequestParams( GAutoReplyParams * pReplyParams )
{
		// reply params
	GParams params = GlobalData::instance()->getParams();
	pReplyParams->setParams( params );
}
// ---------------------------------------------------------------------------


// ----------------- AdjusterServer::processRequestFrame() -------------------
void AdjusterServer::processRequestFrame( GAutoReplyFrame * pReplyFrame )
{
		// setup packet
	pReplyFrame->setImage( GlobalData::instance()->getImage() );
		// NOTE jpeg may have another size
	pReplyFrame->setWidth( GlobalData::instance()->getImageWidth() );
	pReplyFrame->setHeight( GlobalData::instance()->getImageHeight() );
}
// ---------------------------------------------------------------------------


// ----------------- AdjusterServer::processUdpTarget() ----------------------
void AdjusterServer::processUdpTarget( GUDPHostInfo* pHostInfo )
{
	if ( pHostInfo )
	{
		GlobalData::instance()->setUpdAddress( pHostInfo->hostAddress(),
							 				   pHostInfo->port()
											 );
	}
	else 
	{
		qWarning("Server::processUdpTarget: null packet");
	}
}
// ---------------------------------------------------------------------------



// eof
